1、 SPI 框架
	SPI 框架包括以下几个部分：
	1） SPI 核心；管理 SPI 控制器驱动驱动和 SPI 设备驱动，此部分由linux提供
	2） SPI 控制器驱动：用于驱 SOC 上的SPI控制器，此部分由主控芯片厂家提供
	3） SPI 设备：用于描述 SPI 设备信息和此设备对SPI总线的配置，一般在设备树中编写。
	4） SPI 设备驱动：用于驱动 SPI 总线上的设备，一移植厂家驱动或自己编写
2、 SPI 控制器驱动
	对象 struct spi_controller 表示一个 SPI 控制器，其核心成员如下：
	//配置SPI控制器
	int (*setup)(struct spi_device *spi);
	//SPI数据包传输
	int (*transfer)(struct spi_device *spi, struct spi_message *mesg);
	//总线编号
	s16 bus_num;
	//片选数量，从设备的片选号不能大于这个数量
	u16 num_chipselect;
	//指示此控制器是否时从设备
	bool slave;
	//控制器所支持的模式
	u32 mode_bits;
	SPI 控制器驱动的核心就是完成对 struct spi_controller 的分配和初始化，然后将其添加到系统中，如下是
分配 SPI 控制器并向系统添加和删除 SPI 控制器驱动的函数
	//分配SPI控制器
	struct spi_controller *spi_alloc_master(struct device *host, unsigned int size)
	struct spi_controller *spi_alloc_slave(struct device *host, unsigned int size)
	//释放SPI控制器
	void spi_controller_put(struct spi_controller *ctlr)
	#define spi_master_put(_ctlr)		spi_controller_put(_ctlr)
	//注册SPI控制器
	int spi_register_master(struct spi_controller *ctlr)
	//注销SPI控制器
	void spi_unregister_master(struct spi_controller *ctlr)
3、 SPI 设备驱动
	SPI 设备用 struct spi_device 表示，它用于描述一个 SPI 设备， SPI 设备驱动用 struct spi_driver 表示，它用
于描述 SPI 设备的驱动。
	struct spi_device 的核心成员如下：
		//继承的device对象
		struct device dev;
		//所属控制器
		struct spi_controller *controller;
		//最大总线频率
		u32 max_speed_hz;
		//片选号，与控制器的片选列表对应
		u8 chip_select;
		//总线模式
		u32 mode;
		//片选引脚，不使用时为-ENOENT
		int cs_gpio;
		//驱动程序的名称或别名
		char modalias[SPI_NAME_SIZE];
		//强制匹配字符串
		const char *driver_override;
	struct spi_driver 的核心成员如下：
		//ID匹配表
		const struct spi_device_id *id_table;
		//设备和驱动匹配成功执行
		int (*probe)(struct spi_device *spi);
		//设备或驱动卸载执行
		int (*remove)(struct spi_device *spi);
		//继承的device_driver
		struct device_driver driver;
	//注册SPI设备驱动
	int spi_register_driver(struct spi_driver *sdrv)
	//注销SPI设备驱动
	void spi_unregister_driver(struct spi_driver *sdrv)
4、 SPI 设备和驱动匹配过程
	如下时SPI设备和驱动的匹配过程：
	static int spi_match_device(struct device *dev, struct device_driver *drv)
	{
		const struct spi_device	*spi = to_spi_device(dev);
		const struct spi_driver	*sdrv = to_spi_driver(drv);

		//采用driver_override进行强制匹配
		if (spi->driver_override)
			return strcmp(spi->driver_override, drv->name) == 0;

		//设备树匹配
		if (of_driver_match_device(dev, drv))
			return 1;

		//ACPI匹配
		if (acpi_driver_match_device(dev, drv))
			return 1;

		//id_table匹配
		if (sdrv->id_table)
			return !!spi_match_id(sdrv->id_table, spi);

		//采用驱动程序的名称匹配
		return strcmp(spi->modalias, drv->name) == 0;
	}
5、 SPI 设备传输数据
	SPI 设备采用 struct spi_transfer 描述一个数据包，其核心成员如下：
		//发送缓存
		const void *tx_buf;
		//接收缓存
		void *rx_buf;
		//缓存长度
		unsigned len;
		//此次传输完成后是否重新获取片选并配置
		unsigned cs_change;
		//片选无效时间
		u16 cs_change_delay;
		//cs_change_delay的延时单位，由us、ns、clk3种选择
		u8 cs_change_delay_unit;
		//字长
		u8 bits_per_word;
		//每个字传输完成后延迟多少us
		u8 word_delay_usecs;
		//每个字传输完成后延迟多少个时钟周期
		u16 word_delay;
		//在此传输后更改片选状态前之前延迟多少us
		u16 delay_usecs;
		//时钟速率
		u32 speed_hz;
		//spi_transfer链表节点
		struct list_head transfer_list;
	struct spi_transfer 描述的是单个数据包，在 SPI 框架中还需要利用 struct spi_message 将一个或多个数据包组合
成一个 message 后才能进行发送， struct spi_message 的核心成员如下：
		//要传输的数据包链表
		struct list_head transfers;
		//传输完成回调函数
		void (*complete)(void *context);
	SPI 传输数据相关的函数如下：
		//初始化一个SPI message
		void spi_message_init(struct spi_message *m)
		//向SPI message中添加一个数据包
		void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
		//启动SPI，进行同步传输
		int spi_sync(struct spi_device *spi, struct spi_message *message)
		//启动SPI，进行异步传输，传输完成后调用void (*complete)(void *context)函数
		int spi_async(struct spi_device *spi, struct spi_message *message)
6、 SPI 设备树
	在那条 SPI 总线下挂载设备就在那条总线的设备树节点下添加对应设备的子节点，节点命名规则 [标签:]名称[@地址]，
节点内容必须包含 reg 属性、 compatible 属性、 spi-max-frequency 属性， reg 属性用于描述片选索引， compatible
属性用于设备和驱动的匹配， spi-max-frequency 用于描述设备可支持的最大 SPI 总线频率，如下是在 SPI1 中添加一个
icm20608 设备节点的示例：
&spi1 {
	//描述SPI控制器引脚和片选引脚，并使能I2C控制器
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&spi1_pins_a>;
	pinctrl-1 = <&spi1_sleep_pins_a>;
	cs-gpios = <&gpioz 3 GPIO_ACTIVE_LOW>;
	status = "okay";

	//描述icm20608设备
	spidev: icm20608@0 {
		compatible = "alientek,icm20608";
	 	reg = <0>;						/* CS #0 */
	 	spi-max-frequency = <8000000>;	/* 最大时钟频率 */
		spi-cpha;						/* cpha=1 */
		spi-cpol;						/* cpol=1 */
		spi-cs-high;					/* 片选高电平有效 */
		spi-lsb-first;					/* 低位在前 */
		spi-rx-bus-width = <2>;			/* 接收数据宽度为2B */
		spi-tx-bus-width = <2>;			/* 发送数据宽度为2B */
	};
};
7、 部分芯片SPI的自动片选可能存在BUG，此时应自己使用GPIO作为片选控制